<?php

namespace App\Models\Passengers\Repositories;

use App\Jobs\Passenger\ProcessPassengerGoCheck;
use App\Models\Passengers\Passenger;
use App\Trip\IdentityCode\IdentityCode;
use App\Trip\Passengers\CommonPassengerManager;
use App\Trip\Passengers\PassengerCheck;
use App\Trip\Passengers\Passengers;
use App\Trip\Repository\BaseRepository;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;

class PassengerRepository extends BaseRepository implements Interfaces\PassengerRepositoryInterface
{
    public function __construct(Passenger $model)
    {
        parent::__construct($model);
    }

    /**
     * @throws Exception
     */
    public function listAll(array $condition, ?int $limit = 0): Collection
    {
        $validator = Validator::make($condition,
            [
                'user_id' => "required",
            ]
        );

        if ($validator->fails()) {
            throw new Exception("param error");
        }

        return $this->model
            ->when(!empty($condition['passenger_ids']), function ($query) use ($condition) {
                $query->whereIn('passenger_id', $condition['passenger_ids']);
            })
            ->when(!empty($condition['passenger_type']), function ($query) use ($condition) {
                if (is_array($condition['passenger_type'])) {
                    $query->whereIn('passenger_type', $condition['passenger_type']);
                } else if (is_numeric($condition['passenger_type'])) {
                    $query->where('passenger_type', $condition['passenger_type']);
                }
            })
            ->when(!empty($condition['verify_state']), function ($query) use ($condition) {
                if (is_array($condition['verify_state'])) {
                    $query->whereIn('verify_state', $condition['verify_state']);
                } else if (is_numeric($condition['verify_state'])) {
                    $query->where('verify_state', $condition['verify_state']);
                }
            })
            ->where('user_id', $condition['user_id'])
            ->where('delete_state', Passenger::DELETE_STATE_NORMAL)
            ->when($limit > 0, function ($query) use ($limit) {
                $query->limit($limit);
            })
            ->orderByDesc('id')
            ->get();
    }

    /**
     * @throws Exception
     */
    public function addPassenger(array $param): Passenger
    {
        $pm                    = new CommonPassengerManager();
        $param['passenger_id'] = $pm->generatePassengerIdByIdentityCode($param['identity_code']);
        $this->validator($param);

        if ($passenger = $this->findOneByPassengerIdAndUserId($param['passenger_id'], $param['user_id'])) {
            $this->updatePassenger($passenger, $param);
            return $passenger;
        }

        /**
         * 默认不核验
         */
        $param['verify_state'] = Passenger::VERIFY_STATE_VERIFIED;
        // 根据身份证号 计算生日 和性别
        if ($param['identity_type'] == 1) {
            $identity           = new IdentityCode($param['identity_code']);
            $param['birth_day'] = $identity->getBirthDay();
            $param['gender']    = $identity->getSex();
            /**
             * 目前身份证需要核验姓名
             */
            $param['verify_state'] = Passenger::VERIFY_STATE_WAITING;
            // 核验身份证
            $passengerCheck = new PassengerCheck($param['identity_code'], $param['truename']);
        }

        $passenger = $this->create($param);
        if ($passenger->getIdentityType() == 1 && $passenger->isWaitingVerify()) {
            isset($passengerCheck) && ProcessPassengerGoCheck::dispatch($passenger, $passengerCheck);
        }
        return $passenger;
    }

    /**
     * @throws Exception
     */
    private function validator(array &$param)
    {

        $valid_passenger_types = Passenger::getAddPassengerTypeString();
        $valid_identity_types  = Passenger::getIdentityTypeString();
        $param['truename']     = Passengers::dealTrueName($param);
        $valid_data            = [
            'user_id'        => "required",
            'truename'       => "required|min:2",
            'identity_type'  => "required|in:{$valid_identity_types}",
            'identity_code'  => "required|passengers_identify_number:identity_type",
            'passenger_type' => "required|in:{$valid_passenger_types}",
            'mobile'         => "required|phone",
        ];
        if (isset($param['passenger_id'])) {
            $valid_data['passenger_id'] = "required";
        }
        $validator = Validator::make($param,
            $valid_data,
            [
                "identity_type.in"                         => "证件类型错误",
                "passenger_type.in"                        => "乘客类型错误",
                "identity_code.passengers_identify_number" => "证件号错误",
                "mobile.required"                          => "请填写手机号",
                "mobile.phone"                             => "手机号格式错误",
            ]
        );

        if ($validator->fails()) {
            throw new Exception($validator->errors()->first());
        }
    }

    public function findOneByPassengerIdAndUserId(string $passenger_id, string $user_id): ?Passenger
    {
        return $this->findOneBy([
            'passenger_id' => $passenger_id,
            'user_id'      => $user_id,
        ]);
    }

    /**
     * @throws Exception
     */
    public function updatePassenger(Passenger $passenger, array $param): bool
    {
        $this->validator($param);
        // 如果乘客的身份证发生变化 新增
        if ($param['identity_code'] != $passenger->getIdentityCode()) {
            $this->addPassenger($param);
            return true;
        }

        // 如果乘客之前被删除了 恢复
        if ($passenger->isDeleted()) {
            $param["delete_state"] = Passenger::DELETE_STATE_NORMAL;
            $param["deleted_at"]   = null;
        }


        $isChangeName = $passenger->getTrueName() != $param['truename'];
        if ($passenger->isVerified() && $isChangeName) {
            throw new Exception("用户已核验身份证号和姓名，无法修改");
        }

        // 根据身份证号 计算生日 和性别
        $param['verify_state'] = $passenger->getVerifyState();
        if ($param['identity_type'] == 1) {
            $identity           = new IdentityCode($param['identity_code']);
            $param['birth_day'] = $identity->getBirthDay();
            $param['gender']    = $identity->getSex();


            try {
                // 如果有正确结果的情况下
                $passengerCheck = new PassengerCheck($param['identity_code'], $param['truename']);
            } catch (Exception $e) {
                throw new Exception($e->getMessage());
            }

            if ($passenger->isVerifyFailed() && $isChangeName) {
                $param['verify_state'] = Passenger::VERIFY_STATE_WAITING;
            }
        }

        $res = $this->update($param, $passenger);
        if ($param['verify_state'] == Passenger::VERIFY_STATE_WAITING && isset($passengerCheck)) {
            ProcessPassengerGoCheck::dispatch($passenger, $passengerCheck);
        }

        return $res;

    }

    /**
     * @throws Exception
     */
    public function destroy(Passenger $passenger): bool
    {
        return $this->update([
            'deleted_at'   => Carbon::now(),
            'delete_state' => Passenger::DELETE_STATE_DELETED,
        ],
            $passenger);
    }

    public function findOneByIdentityCodeAndUserId(string $identity_code, string $user_id): ?Passenger
    {
        return $this->findOneBy([
            'identity_code' => $identity_code,
            'user_id'       => $user_id,
        ]);
    }

    public function updateVerifyState(Passenger $passenger, int $verify_state): bool
    {
        return $this->update([
            'verify_state' => $verify_state,
        ], $passenger);
    }
}